feat(ci): harden the reusable workflows and stubs - #65
Merged
Conversation
- pin the runtime commitlint installs to exact versions - npx --no-install for vitest and semantic-release (fail loudly, never fetch latest) - timeout-minutes on every central job - explicit stub secret mappings replacing secrets: inherit (4 stubs pass none) - format gate job in reusable-ci (prettier --check, CI_SKIP_FORMAT opt-out) - alert-on-failure issue-filing job in reusable-release (ported from nswds-ui)
✅ Snyk checks have passed. No issues have been found so far.
💻 Catch issues earlier using the plugins for VS Code, JetBrains IDEs, Visual Studio, and Eclipse. |
There was a problem hiding this comment.
Pull request overview
This PR hardens the GitHub Actions reusable workflows and their stub callers to reduce secret exposure risk, improve supply-chain safety, and prevent hung CI/release jobs from blocking the fleet.
Changes:
- Replaced
secrets: inheritin stubs/callers with least-privilege explicit secret mappings (or removed secrets entirely where unused). - Added
timeout-minutesacross jobs and tightenednpxusage with--no-install; pinned commitlint install versions. - Added a reusable CI
formatgate (Prettier) and a reusable releasealert-on-failurejob that files/bumps arelease-failureissue.
Reviewed changes
Copilot reviewed 24 out of 24 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| workflow-stubs/validate-branch-name.yml | Removes secrets: inherit from the validate-branch-name stub. |
| workflow-stubs/release.yml | Maps only RELEASE_DEPLOY_KEY explicitly for release stub. |
| workflow-stubs/openai-pr-description.yml | Maps only OPENAI_API_KEY explicitly for OpenAI PR description stub. |
| workflow-stubs/commitlint.yml | Removes secrets: inherit from commitlint stub. |
| workflow-stubs/commit-types-sync.yml | Removes secrets: inherit from commit-types-sync stub. |
| workflow-stubs/ci.yml | Removes secrets: inherit from CI stub. |
| workflow-stubs/ai-pr-title.yml | Maps only OPENAI_API_KEY explicitly for AI PR title stub. |
| .github/workflows/validate-branch-name.yml | Removes secrets: inherit from local reusable caller. |
| .github/workflows/sync.yml | Adds job timeout for the sync workflow. |
| .github/workflows/reusable-validate-branch-name.yml | Adds a timeout to reusable validate-branch-name. |
| .github/workflows/reusable-release.yml | Adds timeouts, --no-install semantic-release, and a release-failure alert job. |
| .github/workflows/reusable-openai-pr-description.yml | Updates secret description and adds a timeout. |
| .github/workflows/reusable-commitlint.yml | Adds a timeout to reusable commitlint. |
| .github/workflows/reusable-commit-types-sync.yml | Adds a timeout and pins commitlint install versions. |
| .github/workflows/reusable-ci.yml | Adds job timeouts, introduces format job, and uses --no-install for vitest. |
| .github/workflows/reusable-ai-pr-title.yml | Updates secret description, adds a timeout, and pins commitlint install versions. |
| .github/workflows/release.yml | Replaces secrets: inherit with explicit RELEASE_DEPLOY_KEY mapping. |
| .github/workflows/openai-pr-description.yml | Replaces secrets: inherit with explicit OPENAI_API_KEY mapping. |
| .github/workflows/confluence-sync.yml | Adds a job timeout for confluence sync. |
| .github/workflows/commitlint.yml | Removes secrets: inherit from local commitlint caller. |
| .github/workflows/commit-types-sync.yml | Removes secrets: inherit from local commit-types-sync caller. |
| .github/workflows/ci.yml | Adds timeouts to internal linting jobs. |
| .github/workflows/ccc-v10-canary.yml | Adds a timeout to the canary probe job. |
| .github/workflows/ai-pr-title.yml | Replaces secrets: inherit with explicit OPENAI_API_KEY mapping. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Comment on lines
+95
to
+97
| name: File release-failure issue | ||
| needs: release | ||
| if: failure() |
Comment on lines
+136
to
+140
| if ls .prettierrc .prettierrc.* prettier.config.* >/dev/null 2>&1; then | ||
| present=true | ||
| elif [ -f package.json ] && node -e "process.exit(require('./package.json').prettier ? 0 : 1)"; then | ||
| present=true | ||
| fi |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Batch A of the fleet remediation (single PR = single sync fan-out wave).
Reusables
npm install @commitlint/*lines are pinned exact (21.2.1 / 21.2.0);npx vitest runandnpx semantic-releasegain--no-installso a missing local dependency fails loudly instead of executing latest from the registry (all 24 consumers carry semantic-release; the only vitest config in the fleet has its dep).timeout-minuteson every job (10 lint-class / 15 install / 20 test / 30 release) — a hung release previously held the serialized release queue for up to 6h.formatjob in reusable-ci:npx --no-install prettier --check .when the repo has a Prettier config (file or package.jsonprettierkey — probe step, same pattern as the npm-test probe).CI_SKIP_FORMAT=trueopt-out. Advisory context (install / format) until repos add it to rulesets.alert-on-failurejob in reusable-release (ported from nswds-ui's bespoke release.yml): every release failure files/bumps a labelled issue instead of failing silently post-merge.Stubs (fan out via sync)
secrets: inheritreplaced with explicit mappings:OPENAI_API_KEY(ai-pr-title, openai-pr-description),RELEASE_DEPLOY_KEY(release); removed entirely from ci/commitlint/validate-branch-name/commit-types-sync, which consume no secrets. Verified safe against live@v1— the reusables already declare these as optionalworkflow_callsecrets. This is what turns a hypothetical v1-tag compromise from CI-tampering into not org-wide secret exfiltration.Notes
create-github-app-token@v3— watching it.actionlint -ignore SC2016clean on workflows and the stub scratch tree.